﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;

namespace Sync_MD5Check
{
    class SyncEngine
    {
        #region Attributes

        private string _firstPath;
        private string _secondPath;
        public List<CompareResult> _results;

        #endregion

        #region Methods

        public SyncEngine()
        {
            _firstPath = _secondPath = "";
            _results = new List<CompareResult>();
        }

        public void startEngine(string firstPath, string secondPath)
        {
            _firstPath = firstPath;
            _secondPath = secondPath;
            startEngine();
        }

        public void startEngine()
        {
            try
            {
                firstScan();
                secondScan();
            }
            catch (Exception e)
            {
                Console.WriteLine(e.ToString());
                Console.ReadKey();
            }
        }

        public void displayDebugResults()
        {
            foreach (CompareResult result in _results)
            {
                Console.Write("Files " + result.FirstFile.FullName + " - " + result.SecondFile.FullName);
                Console.WriteLine(" = " + result.ResultInfo.ToString());
            }
        }

        private void firstScan()
        {
            DirectoryInfo dTemp = new DirectoryInfo(_firstPath);
            FileInfo[] files = dTemp.GetFiles("*", SearchOption.AllDirectories);

            foreach (FileInfo file in files)
            {
                string newFileName = file.FullName.Replace(_firstPath, _secondPath);
                FileInfo newFileInfo = new FileInfo(newFileName);

                CompareResult result = new CompareResult();
                result.FirstFile = file;
                result.SecondFile = newFileInfo;

                Debug.Write("Comparaison " + file.FullName + " - " + newFileInfo.FullName);

                if (newFileInfo.Exists)
                {
                    if (GetMD5HashFromFile(newFileName) != GetMD5HashFromFile(file.FullName))
                    {
                        result.ResultInfo = CompareResult.Result.MD5_DIFF;
                        Debug.WriteLine(" = MD5 is different.");
                    }
                    else
                    {
                        result.ResultInfo = CompareResult.Result.SAME_FILE;
                        Debug.WriteLine(" = same file.");
                    }
                }
                else
                {
                    result.ResultInfo = CompareResult.Result.NOTFOUND_SECONDDIR;
                    Debug.WriteLine(" = Not Found in the second dir.");
                }
                _results.Add(result);
            }
        }

        private void secondScan()
        {
            DirectoryInfo dTemp = new DirectoryInfo(_secondPath);
            FileInfo[] files = dTemp.GetFiles("*", SearchOption.AllDirectories);

            foreach (FileInfo file in files)
            {
                string newFileName = file.FullName.Replace(_secondPath, _firstPath);
                FileInfo newFileInfo = new FileInfo(newFileName);

                Debug.Write("Comparaison " + file.FullName + " - " + newFileInfo.FullName);

                CompareResult result = new CompareResult();
                result.FirstFile = newFileInfo;
                result.SecondFile = file;

                bool find = false;
                for (int it = 0; it < _results.Count; it++)
                {
                    if (_results[it].FirstFile.FullName == newFileInfo.FullName)
                    {
                        find = true;
                        Debug.WriteLine(" = already know ; " + _results[it].ResultInfo.ToString());
                        break;
                    }
                }

                if (find)
                    continue;

                result.ResultInfo = CompareResult.Result.NOTFOUND_FIRSTDIR;
                Debug.WriteLine(" = not found in the first dir.");
                _results.Add(result);
            }
        }

        private string GetMD5HashFromFile(string fileName)
        {
            FileStream file = new FileStream(fileName, FileMode.Open);
            MD5 md5 = new MD5CryptoServiceProvider();
            byte[] retVal = md5.ComputeHash(file);
            file.Close();

            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < retVal.Length; i++)
                sb.Append(retVal[i].ToString("x2"));
            return sb.ToString();
        }

        #endregion

        #region Get & Set

        public string FirstPath
        {
            get { return _firstPath; }
            set { _firstPath = value; }
        }

        public string SecondPath
        {
            get { return _secondPath; }
            set { _secondPath = value; }
        }

        #endregion
    }
}
